package cn.sherer.utils;

import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.Handler;
import java.util.logging.Formatter;
import java.util.logging.LogRecord;
import javax.servlet.ServletContext;
import java.util.logging.FileHandler;
import javax.servlet.http.HttpServletRequest;

/**
 * 日志工具类
 */
public class LogUtils {
    private static final String ROOT = "/logs";
    private static final Level OUT_LEVEL = Level.ALL;

    private String path = "";
    private String folder = "";
    private String name = "";
    private Level outLevel = OUT_LEVEL;

    public LogUtils() {
    }

    public LogUtils(HttpServletRequest request) {
        this(request, "", "", OUT_LEVEL);
    }

    public LogUtils(ServletContext context) {
        this(context, "", "", OUT_LEVEL);
    }

    public LogUtils(HttpServletRequest request, String name) {
        this(request, "", name, OUT_LEVEL);
    }

    public LogUtils(ServletContext context, String name) {
        this(context, "", name, OUT_LEVEL);
    }

    public LogUtils(HttpServletRequest request, Level outLevel) {
        this(request, "", "", outLevel);
    }

    public LogUtils(ServletContext context, Level outLevel) {
        this(context, "", "", outLevel);
    }

    public LogUtils(HttpServletRequest request, String name, Level outLevel) {
        this(request, "", name, outLevel);
    }

    public LogUtils(ServletContext context, String name, Level outLevel) {
        this(context, "", name, outLevel);
    }

    public LogUtils(HttpServletRequest request, String folder, String name) {
        this(request, folder, name, OUT_LEVEL);
    }

    public LogUtils(ServletContext context, String folder, String name) {
        this(context, folder, name, OUT_LEVEL);
    }

    public LogUtils(HttpServletRequest request, String folder, String name, Level outLevel) {
        this(request.getServletContext(), folder, name, outLevel);
    }

    public LogUtils(ServletContext context, String folder, String name, Level outLevel) {
        this(context, ROOT, folder, name, outLevel);
    }

    public LogUtils(HttpServletRequest request, String root, String folder, String name, Level outLevel) {
        this(request.getServletContext(), root, folder, name, outLevel);
    }

    public LogUtils(ServletContext context, String root, String folder, String name, Level outLevel) {
        this(context.getRealPath(root), folder, name, outLevel);
    }

    public LogUtils(String path, String folder, String name, Level outLevel) {
        this.path = path;
        this.folder = folder;
        this.name = name;
        this.outLevel = outLevel;
    }


    public String getPath() {
        return path;
    }
    public void setPath(String path) {
        this.path = path;
    }

    public String getFolder() {
        return folder;
    }
    public void setFolder(String folder) {
        this.folder = folder;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public Level getOutLevel() {
        return outLevel;
    }
    public void setOutLevel(Level outLevel) {
        this.outLevel = outLevel;
    }


    /**
     * 写调试日志
     * @param msg 日志内容
     */
    public void info(String msg) {
        info(name, msg);
    }

    /**
     * 写警告日志
     * @param msg 日志内容
     */
    public void warn(String msg) {
        warn(name, msg);
    }

    /**
     * 写错误日志
     * @param msg 日志内容
     */
    public void error(String msg) {
        error(msg, null);
    }


    /**
     * 写错误日志
     * @param msg 日志内容
     * @param thrown 异常
     */
    public void error(String msg, Throwable thrown) {
        error(name, msg, thrown);
    }


    /**
     * 写调试日志
     * @param name 日志名称
     * @param msg 日志内容
     */
    public void info(String name, String msg) {
        info(name, msg, outLevel);
    }

    /**
     * 写警告日志
     * @param name 日志名称
     * @param msg 日志内容
     */
    public void warn(String name, String msg) {
        warn(name, msg, outLevel);
    }

    /**
     * 写错误日志
     * @param name 日志名称
     * @param msg 日志内容
     * @param thrown 异常
     */
    public void error(String name, String msg, Throwable thrown) {
        error(name, msg, thrown, outLevel);
    }


    /**
     * 写调试日志
     * @param name 日志名称
     * @param msg 日志内容
     * @param outLevel 输出级别
     */
    public void info(String name, String msg, Level outLevel) {
        info(name, msg, path + "/" + folder, outLevel);
    }

    /**
     * 写警告日志
     * @param name 日志名称
     * @param msg 日志内容
     * @param outLevel 输出级别
     */
    public void warn(String name, String msg, Level outLevel) {
        warn(name, msg, path + "/" + folder, outLevel);
    }

    /**
     * 写错误日志
     * @param name 日志名称
     * @param msg 日志内容
     * @param thrown 异常
     * @param outLevel 输出级别
     */
    public void error(String name, String msg, Throwable thrown, Level outLevel) {
        error(name, msg, thrown, path + "/" + folder, outLevel);
    }


    /**
     * 写调试日志
     * @param name 日志名称
     * @param msg 日志内容
     * @param path 日志路径
     */
    public static void info(String name, String msg, String path) {
        info(name, msg, path, OUT_LEVEL);
    }

    /**
     * 写警告日志
     * @param name 日志名称
     * @param msg 日志内容
     * @param path 日志路径
     */
    public static void warn(String name, String msg, String path) {
        warn(name, msg, path, OUT_LEVEL);
    }

    /**
     * 写错误日志
     * @param name 日志名称
     * @param msg 日志内容
     * @param path 日志路径
     */
    public static void error(String name, String msg, String path) {
        error(name, msg, null, path, OUT_LEVEL);
    }


    /**
     * 写错误日志
     * @param name 日志名称
     * @param msg 日志内容
     * @param path 日志路径
     * @param outLevel 输出级别
     */
    public static void error(String name, String msg, String path, Level outLevel) {
        error(name, msg, null, path, outLevel);
    }


    /**
     * 写调试日志
     * @param name 日志名称
     * @param msg 日志内容
     * @param path 日志路径
     * @param outLevel 输出级别
     */
    public static void info(String name, String msg, String path, Level outLevel) {
        write(name, Level.INFO, msg, null, path, outLevel);
    }

    /**
     * 写警告日志
     * @param name 日志名称
     * @param msg 日志内容
     * @param path 日志路径
     * @param outLevel 输出级别
     */
    public static void warn(String name, String msg, String path, Level outLevel) {
        write(name, Level.WARNING, msg, null, path, outLevel);
    }

    /**
     * 写错误日志
     * @param name 日志名称
     * @param msg 日志内容
     * @param thrown 异常
     * @param path 日志路径
     * @param outLevel 输出级别
     */
    public static void error(String name, String msg, Throwable thrown, String path, Level outLevel) {
        write(name, Level.SEVERE, msg, thrown, path, outLevel);
    }


    /**
     * 写日志
     * @param name 日志名称
     * @param level 日志级别
     * @param msg 日志内容
     * @param thrown 异常
     * @param path 日志路径
     * @param outLevel 输出级别
     */
    public static void write(String name, Level level, String msg, Throwable thrown, String path, Level outLevel) {
        // 获取日志记录器
        Logger logger = Logger.getLogger(name);
        logger.setLevel(outLevel);

        // 设置文件输出
        FileHandler fileHandler = null;
        if (path != null && !path.trim().equals("")) {
            if (path.startsWith("/")) {
                path = path.substring(1);
            }

            if (path.endsWith("/")) {
                path = path.substring(0, path.length() - 1);
            }

            try {
                for (Handler handler : logger.getHandlers()) {
                    logger.removeHandler(handler);
                }

                path += System.getProperty("file.separator") + DateUtils.getToday(DateUtils.FORMAT_DATE) + ".log";
                File file = new File(path);
                if (!file.getParentFile().exists()) {
                    file.getParentFile().mkdirs();
                }

                fileHandler = new FileHandler(path, true);
                logger.addHandler(fileHandler);
            } catch (SecurityException | IOException e) {
                Logger.getLogger(LogUtils.class.getName()).log(Level.SEVERE, "", e);
            }
        }

        // 设置输出格式
        if (fileHandler != null) {
            fileHandler.setFormatter(new Formatter() {
                @Override
                public String format(LogRecord record) {
                    StringBuilder sb = new StringBuilder();
                    String levelString = record.getLevel().getName().toUpperCase();
                    levelString = levelString.equalsIgnoreCase("SEVERE") ? "ERROR" : levelString;
                    levelString = levelString.equalsIgnoreCase("WARNING") ? "WARN" : levelString;
                    sb.append(DateUtils.getToday(DateUtils.FORMAT_LONG_DATE_TIME));
                    sb.append(StringUtils.isNull(name, "").trim().equals("") ? "" : " " + name).append(" " + levelString);
                    sb.append(StringUtils.isNull(record.getMessage(), "").trim().equals("") ? "" : " " + record.getMessage());
                    sb.append(record.getThrown() == null ? "" : System.getProperty("line.separator") + record.getThrown()).append(System.getProperty("line.separator"));
                    return sb.toString();
                }
            });
        }

        // 输出日志
        logger.log(level, msg, thrown);

        // 关闭文件输出
        if (fileHandler != null) {
            fileHandler.close();
        }
    }
}
